package org.dromara.exam.util;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.volcengine.ark.runtime.service.ArkService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.exam.domain.bo.QuestionGenerateBo;
import org.dromara.exam.domain.dto.TemplateSchema;
import org.dromara.exam.domain.vo.ExamTemplateVo;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author xiyin321
 * @since 2025/1/22
 */
@Slf4j
public class DoubaoScoringUtils {
    // 用于存储生成的唯一ID
    private static final Set<String> ids = new HashSet<>();
    // 常量定义，避免硬编码
    private static final String TITLE_PREFIX = "题目:";
    private static final String TYPE_PREFIX = "题型:";
    private static final String OPTIONS_PREFIX = "选项:";
    private static final String ANSWER_PREFIX = "正确答案:";
    private static final String ANALYSIS_PREFIX = "解析:";
    private static final String TAG_PREFIX = "标签:";

    // 题型配置常量
    private static final Map<String, QuestionTypeConfig> TYPE_CONFIG_MAP = new HashMap<>();


    static {
        TYPE_CONFIG_MAP.put("Radio", new QuestionTypeConfig(
            TemplateSchema.QuestionType.Radio, 1L,
            TemplateSchema.ExamScoreMode.onlyOne, 5.0, null
        ));
        TYPE_CONFIG_MAP.put("TrueFalse", new QuestionTypeConfig(
            TemplateSchema.QuestionType.TrueFalse, 3L,
            TemplateSchema.ExamScoreMode.onlyOne, 5.0, null
        ));
        TYPE_CONFIG_MAP.put("Checkbox", new QuestionTypeConfig(
            TemplateSchema.QuestionType.Checkbox, 2L,
            TemplateSchema.ExamScoreMode.selectAll, 5.0, null
        ));
        TYPE_CONFIG_MAP.put("FillBlank", new QuestionTypeConfig(
            TemplateSchema.QuestionType.FillBlank, 4L,
            TemplateSchema.ExamScoreMode.selectAll, 5.0,
            TemplateSchema.ExamMatchRule.completeSame
        ));
        TYPE_CONFIG_MAP.put("MultipleBlank", new QuestionTypeConfig(
            TemplateSchema.QuestionType.MultipleBlank, 4L,
            TemplateSchema.ExamScoreMode.selectAll, 5.0,
            TemplateSchema.ExamMatchRule.completeSame
        ));
        TYPE_CONFIG_MAP.put("Textarea", new QuestionTypeConfig(
            TemplateSchema.QuestionType.Textarea, 5L,
            TemplateSchema.ExamScoreMode.ai, 5.0,
            TemplateSchema.ExamMatchRule.completeSame
        ));
    }

    // 配置类定义
    @RequiredArgsConstructor
    @Getter
    private static class QuestionTypeConfig {
        private final TemplateSchema.QuestionType type;
        private final Long orderNum;
        private final TemplateSchema.ExamScoreMode scoreMode;
        private final Double score;
        private final TemplateSchema.ExamMatchRule matchRule;
    }

    /**
     * 使用豆包API计算简答题得分
     *
     * @param title           题目
     * @param qScore          题目分值
     * @param referenceAnswer 参考答案
     * @param userAnswer      用户答案
     * @return 计算后的得分
     */
    public static Double shortAnswerScoring(String title, Double qScore, String referenceAnswer, Object userAnswer) {
        String sessionToken = CacheUtils.get("sys_config", "sys.doubao.sessionToken");
        String apiKey = CacheUtils.get("sys_config", "sys.doubao.apiKey");
        // 使用豆包API计算简答题得分
        ArkService service = ArkService.builder().apiKey(apiKey).build();

        List<ChatMessage> messages = new ArrayList<>();
        ChatMessage systemMessage = ChatMessage.builder().role(ChatMessageRole.SYSTEM).content("你是一名软件开发工程师").build();
        ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER)
            .content("根据题目、题目分值、参考答案和回答，计算回答所得的分数,如果没有提供参考答案，那么请根据题目给出相应的答案，再对回答进行分数计算，分数计算可以根据小点来计算得分，只需要输出分数，分数为浮点数；" +
                "题目：" + title +
                "题目分值：" + qScore +
                "参考答案：" + referenceAnswer +
                "回答：" + userAnswer).build();
        messages.add(systemMessage);
        messages.add(userMessage);

        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
            .model(sessionToken)
            .messages(messages)
            .build();

        double score = 0.0;
        try {
            // 修改: 将 getContent() 返回的对象转换为 String 类型
            String content = (String) service.createChatCompletion(chatCompletionRequest)
                .getChoices()
                .get(0)
                .getMessage()
                .getContent();
            score = Double.parseDouble(content.trim());
        } catch (Exception e) {
            log.error("调用豆包API计算简答题得分失败", e);
        } finally {
            service.shutdownExecutor();
        }
        System.out.println("豆包API计算得分：" + score);
        // 返回计算后的得分
        return score;
    }

    /**
     * 使用豆包API生成问题列表
     *
     * @param bo 包含生成问题所需参数的对象
     * @return 生成的问题列表字符串
     */
    public static String generateQuestionListByDoubao(QuestionGenerateBo bo) {
        String sessionToken = CacheUtils.get("sys_config", "sys.doubao.sessionToken");
        String apiKey = CacheUtils.get("sys_config", "sys.doubao.apiKey");
        // 使用豆包API生成题目
        ArkService service = ArkService.builder().apiKey(apiKey).build();
        StringBuilder str = new StringBuilder("【出题要求】\n");
        String requirements = bo.getRequirements();
        for (QuestionGenerateBo.ChildrenDTO item : bo.getChildren()) {
            str.append("- ")
                .append(item.getType())
                .append(": ")
                .append(item.getNum())
                .append("道\n");
        }

        String requirementsBuilder = """
            【强制格式要求】
            1. 每个题目必须包含以下字段:题目、题型、选项（如适用）、正确答案、解析、标签
            2. "选择题"选项用英文逗号分隔,例:选项:选项A,选项B,选项C,选项D
            3. "判断题"固定选项:选项:正确,错误
            4. "填空题"答案有且只能有一个，"多项填空"答案必须为两个或者两个以上
            5. "简答题"必须根据题目提供答案,不能为无或者不生成答案
            6. 答案直接写选项内容,多选题用逗号分隔，例：正确答案:选项文本1,选项文本2
            7. 题目和题目之间用换行符进行分隔
            8. 答案解析应该尽可能详细
            9. 标签应当简洁明了,标签个数可以是多个,并且为题目的归纳,同一批次的题目的标签应该有些许相关性,标签字数不超过四个字，多个标签之间使用逗号隔开
            【题目生成示例】
            题目:下列哪个不是编程语言?
            题型:Radio
            选项:HTML,Python,Java,C++
            正确答案:HTML
            解析:HTML是标记语言，不是编程语言
            标签:计算机基础,编程语言

            """;

        List<ChatMessage> messages = new ArrayList<>();
        ChatMessage systemMessage = ChatMessage.builder().role(ChatMessageRole.SYSTEM)
            .content("""
                你是一个专业的智能题目生成系统，严格按照以下规则生成结构化试题:
                1. 绝对遵循用户指定的题型和数量要求
                2. 始终保持固定输出格式
                3. 确保选项和答案的准确性""")
            .build();
        ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER)
            .content(
                "请严格按照以下要求生成试题：\n" +
                    requirementsBuilder
                    + str
                    + requirements
                    + "\n附加要求：\n" +
                    "- 知识点范围：" + bo.getRequirements() + "\n" +
                    "- 绝对禁止：\n" +
                    "  1. 在题目中包含选项内容\n" +
                    "  2. 使用序号标记选项\n").build();

        messages.add(systemMessage);
        messages.add(userMessage);

        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
            .model(sessionToken)
            .messages(messages)
            // 降低随机性
            .temperature(0.3)
            .topP(0.9)
            .build();
        String content = null;
        try {
            // 修改: 将 getContent() 返回的对象转换为 String 类型
            content = (String) service.createChatCompletion(chatCompletionRequest)
                .getChoices()
                .get(0)
                .getMessage()
                .getContent();
        } catch (Exception e) {
            log.error("调用豆包API生成题目失败", e);
        } finally {
            service.shutdownExecutor();
        }
        System.out.println(content);
        return content;
    }

    /**
     * 解析输入字符串为问题列表
     *
     * @param input 包含问题信息的字符串
     * @return 解析后的问题列表
     */
    public static List<ExamTemplateVo> parseQuestions(String input) {
        List<ExamTemplateVo> questionList = new ArrayList<>();
        String[] questionBlocks = input.split("\n\n");

        for (String block : questionBlocks) {
            // 使用Builder初始化
            TemplateSchema question = TemplateSchema.builder().build();
            String[] lines = block.split("\n");

            for (String line : lines) {
                if (line.startsWith(TITLE_PREFIX)) {
                    question.setTitle(line.substring(TITLE_PREFIX.length()));
                } else if (line.startsWith(TYPE_PREFIX)) {
                    handleQuestionType(line.substring(TYPE_PREFIX.length()), question);
                } else if (line.startsWith(OPTIONS_PREFIX)) {
                    handleOptions(line.substring(OPTIONS_PREFIX.length()), question);
                } else if (line.startsWith(ANSWER_PREFIX)) {
                    handleCorrectAnswer(line.substring(ANSWER_PREFIX.length()), question);
                } else if (line.startsWith(ANALYSIS_PREFIX)) {
                    handleAnalysis(line.substring(ANALYSIS_PREFIX.length()), question);
                } else if (line.startsWith(TAG_PREFIX)) {
                    handleTags(line.substring(TAG_PREFIX.length()), question);
                }
            }
            questionList.add(createExamTemplateVo(question));
        }
        return questionList;
    }

    /**
     * 处理题型相关配置
     *
     * @param typeStr  题型字符串
     * @param question 问题对象
     */
    private static void handleQuestionType(String typeStr, TemplateSchema question) {
        QuestionTypeConfig config = TYPE_CONFIG_MAP.get(typeStr);
        if (config == null) return;

        TemplateSchema.Attribute attribute = question.getAttribute();
        attribute.setExamAnswerMode(config.getScoreMode());
        attribute.setExamScore(config.getScore());
        if (config.getMatchRule() != null) {
            attribute.setExamMatchRule(config.getMatchRule());
        }

        question.setType(config.getType());
        question.setOrderNum(config.getOrderNum());
    }

    /**
     * 处理选项
     *
     * @param optionsStr 选项字符串
     * @param question   问题对象
     */
    private static void handleOptions(String optionsStr, TemplateSchema question) {
        if (!isOptionSupported(question.getType())) return;

        List<TemplateSchema> children = Arrays.stream(optionsStr.split(","))
            .map(String::trim)
            .map(opt -> TemplateSchema.builder()
                .id(generateId())
                .title(opt)
                .build())
            .collect(Collectors.toList());
        question.setChildren(children);
    }

    /**
     * 检查题型是否支持选项
     *
     * @param type 题型
     * @return 如果题型支持选项则返回true，否则返回false
     */
    private static boolean isOptionSupported(TemplateSchema.QuestionType type) {
        return type == TemplateSchema.QuestionType.Radio
            || type == TemplateSchema.QuestionType.Checkbox
            || type == TemplateSchema.QuestionType.TrueFalse;
    }

    /**
     * 处理正确答案
     *
     * @param answerStr 正确答案字符串
     * @param question  问题对象
     */
    private static void handleCorrectAnswer(String answerStr, TemplateSchema question) {
        switch (question.getType()) {
            case MultipleBlank,FillBlank:
                handleBlankAnswer(answerStr, question);
                break;
            case Textarea:
                handleTextAnswer(answerStr, question);
                break;
            case Radio:
            case Checkbox:
            case TrueFalse:
                handleChoiceAnswer(answerStr, question);
                break;
        }
    }

    /**
     * 处理填空题的答案
     *
     * @param answerStr 正确答案字符串
     * @param question  问题对象
     */
    private static void handleBlankAnswer(String answerStr, TemplateSchema question) {
        String[] answers = answerStr.split(",");
        List<TemplateSchema> children = IntStream.range(0, answers.length)
            .mapToObj(index -> {
                String answer = answers[index].trim();
                return TemplateSchema.builder()
                    .id(generateId())
                    .title("填空" + (index + 1))
                    .attribute(TemplateSchema.Attribute.builder()
                        .examCorrectAnswer(answer)
                        .build())
                    .build();
            })
            .collect(Collectors.toList());
        question.setChildren(children);
    }

    /**
     * 处理简答题的答案
     *
     * @param answerStr 正确答案字符串
     * @param question  问题对象
     */
    private static void handleTextAnswer(String answerStr, TemplateSchema question) {
        TemplateSchema child = TemplateSchema.builder()
            .id(generateId())
            .attribute(TemplateSchema.Attribute.builder()
                .examCorrectAnswer(answerStr)
                .build())
            .build();
        question.setChildren(Collections.singletonList(child));
    }

    /**
     * 处理选择题的答案
     *
     * @param answerStr 正确答案字符串
     * @param question  问题对象
     */
    private static void handleChoiceAnswer(String answerStr, TemplateSchema question) {
        Set<String> correctAnswers = Arrays.stream(answerStr.split(","))
            .map(String::trim)
            .collect(Collectors.toSet());

        question.getChildren().forEach(child -> {
            TemplateSchema.Attribute attr = child.getAttribute();
            if (correctAnswers.contains(child.getTitle())) {
                attr.setExamCorrectAnswer(child.getId());
            }
            child.setAttribute(attr);
        });
    }

    /**
     * 处理解析
     *
     * @param analysisStr 解析字符串
     * @param question    问题对象
     */
    private static void handleAnalysis(String analysisStr, TemplateSchema question) {
        TemplateSchema.Attribute attribute = question.getAttribute();
        attribute.setExamAnalysis(analysisStr);
        question.setAttribute(attribute);
    }

    /**
     * 处理标签
     *
     * @param tagStr   标签字符串
     * @param question 问题对象
     */
    private static void handleTags(String tagStr, TemplateSchema question) {
        if (StringUtils.isBlank(tagStr)) {
            question.setTags(Collections.emptyList());
        }

        List<String> tags = Arrays.stream(tagStr.split(","))
            .map(String::trim)
            .collect(Collectors.toList());
        question.setTags(tags);
    }

    /**
     * 创建结果对象
     *
     * @param question 问题对象
     * @return 创建的ExamTemplateVo对象
     */
    private static ExamTemplateVo createExamTemplateVo(TemplateSchema question) {
        ExamTemplateVo result = new ExamTemplateVo();
        result.setTemplateId(IdWorker.getId());
        result.setTemplate(question);
        result.setQuestionType(question.getType());
        result.setTemplateName(question.getTitle());
        return result;
    }

    /**
     * 生成一个唯一的ID
     *
     * @return 生成的ID
     */
    private static String generateId() {
        return NanoIdUtils.randomNanoId(4, ids);
    }
}
